home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / cvs-1.8 / cvs-1 / cvs-1.8.1 / os2 / filesubr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-06  |  17.2 KB  |  757 lines

  1. /* filesubr.c --- subroutines for dealing with files under OS/2
  2.    Jim Blandy <jimb@cyclic.com> and Karl Fogel <kfogel@cyclic.com>
  3.  
  4.    This file is part of GNU CVS.
  5.  
  6.    GNU CVS is free software; you can redistribute it and/or modify it
  7.    under the terms of the GNU General Public License as published by the
  8.    Free Software Foundation; either version 2, or (at your option) any
  9.    later version.
  10.  
  11.    This program is distributed in the hope that it will be useful,
  12.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.    GNU General Public License for more details.
  15.  
  16.    You should have received a copy of the GNU General Public License
  17.    along with this program; if not, write to the Free Software
  18.    Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. /* These functions were moved out of subr.c because they need different
  21.    definitions under operating systems (like, say, Windows NT) with different
  22.    file system semantics.  */
  23.  
  24. #include <io.h>
  25.  
  26. #include "cvs.h"
  27.  
  28. /*
  29.  * I don't know of a convenient way to test this at configure time, or else
  30.  * I'd certainly do it there.  -JimB
  31.  */
  32. #if defined(NeXT)
  33. #define LOSING_TMPNAM_FUNCTION
  34. #endif
  35.  
  36. static int deep_remove_dir PROTO((const char *path));
  37.  
  38. /*
  39.  * Copies "from" to "to".
  40.  */
  41. void
  42. copy_file (from, to)
  43.     const char *from;
  44.     const char *to;
  45. {
  46.     struct stat sb;
  47.     struct utimbuf t;
  48.     int fdin, fdout;
  49.  
  50.     if (trace)
  51. #ifdef SERVER_SUPPORT
  52.     (void) fprintf (stderr, "%c-> copy(%s,%s)\n",
  53.             (server_active) ? 'S' : ' ', from, to);
  54. #else
  55.     (void) fprintf (stderr, "-> copy(%s,%s)\n", from, to);
  56. #endif
  57.     if (noexec)
  58.     return;
  59.  
  60.     if ((fdin = open (from, O_RDONLY | O_BINARY)) < 0)
  61.     error (1, errno, "cannot open %s for copying", from);
  62.     if (fstat (fdin, &sb) < 0)
  63.     error (1, errno, "cannot fstat %s", from);
  64.     if ((fdout = open (to, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY,
  65.                        (int) sb.st_mode & 07777)) < 0)
  66.     error (1, errno, "cannot create %s for copying", to);
  67.     if (sb.st_size > 0)
  68.     {
  69.     char buf[BUFSIZ];
  70.     int n;
  71.  
  72.     for (;;) 
  73.     {
  74.         n = read (fdin, buf, sizeof(buf));
  75.         if (n == -1)
  76.         {
  77. #ifdef EINTR
  78.         if (errno == EINTR)
  79.             continue;
  80. #endif
  81.         error (1, errno, "cannot read file %s for copying", from);
  82.         }
  83.             else if (n == 0) 
  84.         break;
  85.   
  86.         if (write(fdout, buf, n) != n) {
  87.         error (1, errno, "cannot write file %s for copying", to);
  88.         }
  89.     }
  90.  
  91. #ifdef HAVE_FSYNC
  92.     if (fsync (fdout)) 
  93.         error (1, errno, "cannot fsync file %s after copying", to);
  94. #endif
  95.     }
  96.  
  97.     if (close (fdin) < 0) 
  98.     error (0, errno, "cannot close %s", from);
  99.     if (close (fdout) < 0)
  100.     error (1, errno, "cannot close %s", to);
  101.  
  102.     /* now, set the times for the copied file to match those of the original */
  103.     memset ((char *) &t, 0, sizeof (t));
  104.     t.actime = sb.st_atime;
  105.     t.modtime = sb.st_mtime;
  106.     (void) utime (to, &t);
  107. }
  108.  
  109. /*
  110.  * link a file, if possible.  Warning: the Windows NT version of this
  111.  * function just copies the file, so only use this function in ways
  112.  * that can deal with either a link or a copy.
  113.  */
  114. int
  115. link_file (from, to)
  116.     const char *from;
  117.     const char *to;
  118. {
  119.     copy_file (from, to);
  120.     return 0;
  121. }
  122.  
  123. /* FIXME-krp: these functions would benefit from caching the char * &
  124.    stat buf.  */
  125.  
  126. /*
  127.  * Returns non-zero if the argument file is a directory, or is a symbolic
  128.  * link which points to a directory.
  129.  */
  130. int
  131. isdir (file)
  132.     const char *file;
  133. {
  134.     struct stat sb;
  135.  
  136.     if (stat (file, &sb) < 0)
  137.     return (0);
  138.     return (S_ISDIR (sb.st_mode));
  139. }
  140.  
  141. /*
  142.  * Returns non-zero if the argument file is a symbolic link.
  143.  */
  144. int
  145. islink (file)
  146.     const char *file;
  147. {
  148. #ifdef S_ISLNK
  149.     struct stat sb;
  150.  
  151.     if (lstat (file, &sb) < 0)
  152.     return (0);
  153.     return (S_ISLNK (sb.st_mode));
  154. #else
  155.     return (0);
  156. #endif
  157. }
  158.  
  159. /*
  160.  * Returns non-zero if the argument file exists.
  161.  */
  162. int
  163. isfile (file)
  164.     const char *file;
  165. {
  166.     struct stat sb;
  167.  
  168.     if (stat (file, &sb) < 0)
  169.     return (0);
  170.     return (1);
  171. }
  172.  
  173. /*
  174.  * Returns non-zero if the argument file is readable.
  175.  * XXX - must be careful if "cvs" is ever made setuid!
  176.  */
  177. int
  178. isreadable (file)
  179.     const char *file;
  180. {
  181.     return (access (file, R_OK) != -1);
  182. }
  183.  
  184. /*
  185.  * Returns non-zero if the argument file is writable
  186.  * XXX - muct be careful if "cvs" is ever made setuid!
  187.  */
  188. int
  189. iswritable (file)
  190.     const char *file;
  191. {
  192.     return (access (file, W_OK) != -1);
  193. }
  194.  
  195. /*
  196.  * Returns non-zero if the argument file is accessable according to
  197.  * mode.  If compiled with SETXID_SUPPORT also works if cvs has setxid
  198.  * bits set.
  199.  */
  200. int
  201. isaccessible (file, mode)
  202.     const char *file;
  203.     const int mode;
  204. {
  205.     return access(file, mode) == 0;
  206. }
  207.  
  208.  
  209. /*
  210.  * Open a file and die if it fails
  211.  */
  212. FILE *
  213. open_file (name, mode)
  214.     const char *name;
  215.     const char *mode;
  216. {
  217.     FILE *fp;
  218.  
  219.     if ((fp = fopen (name, mode)) == NULL)
  220.     error (1, errno, "cannot open %s", name);
  221.     return (fp);
  222. }
  223.  
  224. /*
  225.  * Make a directory and die if it fails
  226.  */
  227. void
  228. make_directory (name)
  229.     const char *name;
  230. {
  231.     struct stat buf;
  232.  
  233.     if (stat (name, &buf) == 0 && (!S_ISDIR (buf.st_mode)))
  234.         error (0, 0, "%s already exists but is not a directory", name);
  235.     if (!noexec && mkdir (name) < 0)
  236.     error (1, errno, "cannot make directory %s", name);
  237. }
  238.  
  239. /*
  240.  * Make a path to the argument directory, printing a message if something
  241.  * goes wrong.
  242.  */
  243. void
  244. make_directories (name)
  245.     const char *name;
  246. {
  247.     char *cp;
  248.  
  249.     if (noexec)
  250.     return;
  251.  
  252.     if (mkdir (name) == 0 || errno == EACCESS)
  253.     return;
  254.     if (! existence_error (errno))
  255.     {
  256.     error (0, errno, "cannot make path to %s", name);
  257.     return;
  258.     }
  259.     if ((cp = strrchr (name, '/')) == NULL)
  260.     return;
  261.     *cp = '\0';
  262.     make_directories (name);
  263.     *cp++ = '/';
  264.     if (*cp == '\0')
  265.     return;
  266.     (void) mkdir (name);
  267. }
  268.  
  269. /*
  270.  * Change the mode of a file, either adding write permissions, or removing
  271.  * all write permissions.  Adding write permissions honors the current umask
  272.  * setting.
  273.  */
  274. void
  275. xchmod (fname, writable)
  276.     char *fname;
  277.     int writable;
  278. {
  279.     char *attrib_cmd;
  280.     char *attrib_option;
  281.     char *whole_cmd;
  282.     char *p;
  283.     char *q;
  284.  
  285.     if (!isfile (fname))
  286.     return ENOENT;
  287.  
  288.     attrib_cmd = "attrib "; /* No, really? */
  289.  
  290.     if (writable)
  291.         attrib_option = "-r ";  /* make writeable */
  292.     else
  293.         attrib_option = "+r ";  /* make read-only */
  294.         
  295.     whole_cmd = xmalloc (strlen (attrib_cmd)
  296.                          + strlen (attrib_option)
  297.                          + strlen (fname)
  298.                          + 1);
  299.  
  300.     strcpy (whole_cmd, attrib_cmd);
  301.     strcat (whole_cmd, attrib_option);
  302.  
  303.     /* Copy fname to the end of whole_cmd, translating / to \.
  304.        Attrib doesn't take / but many parts of CVS rely
  305.        on being able to use it.  */
  306.     p = whole_cmd + strlen (whole_cmd);
  307.     q = fname;
  308.     while (*q)
  309.     {
  310.     if (*q == '/')
  311.         *p++ = '\\';
  312.     else
  313.         *p++ = *q;
  314.     ++q;
  315.     }
  316.     *p = '\0';
  317.  
  318.     system (whole_cmd);
  319.     free (whole_cmd);
  320. }
  321.  
  322.  
  323. /* Read the value of a symbolic link.
  324.    Under OS/2, this function always returns EINVAL.  */
  325. int
  326. readlink (char *path, char *buf, int buf_size)
  327. {
  328.     errno = EINVAL;
  329.     return -1;
  330. }
  331.  
  332. /*
  333.  * unlink a file, if possible.
  334.  */
  335. int
  336. unlink_file (f)
  337.     const char *f;
  338. {
  339.     if (trace)
  340. #ifdef SERVER_SUPPORT
  341.     (void) fprintf (stderr, "%c-> unlink(%s)\n",
  342.             (server_active) ? 'S' : ' ', f);
  343. #else
  344.     (void) fprintf (stderr, "-> unlink(%s)\n", f);
  345. #endif
  346.     if (noexec)
  347.     return (0);
  348.  
  349.    /* Win32 unlink is stupid - it fails if the file is read-only.
  350.     * OS/2 is similarly stupid.  It does have a remove() function,
  351.     * but the documentation does not make clear why remove() is or
  352.     * isn't preferable to unlink().  I'll use unlink() because the
  353.     * name is closer to our interface, what the heck.  Also, we know
  354.     * unlink()'s error code when trying to remove a directory.
  355.     */
  356.     xchmod (f, 1);
  357.     return (unlink (f));
  358. }
  359.  
  360. /*
  361.  * Unlink a file or dir, if possible.  If it is a directory do a deep
  362.  * removal of all of the files in the directory.  Return -1 on error
  363.  * (in which case errno is set).
  364.  */
  365. int
  366. unlink_file_dir (f)
  367.     const char *f;
  368. {
  369.     if (trace)
  370. #ifdef SERVER_SUPPORT
  371.     (void) fprintf (stderr, "%c-> unlink_file_dir(%s)\n",
  372.             (server_active) ? 'S' : ' ', f);
  373. #else
  374.     (void) fprintf (stderr, "-> unlink_file_dir(%s)\n", f);
  375. #endif
  376.     if (noexec)
  377.     return (0);
  378.  
  379.     if (unlink_file (f) != 0)
  380.     {
  381.     /* under OS/2, unlink returns EACCESS if the path
  382.        is a directory.  */
  383.         if (errno == EACCESS)
  384.                 return deep_remove_dir (f);
  385.         else
  386.         /* The file wasn't a directory and some other
  387.          * error occured
  388.          */
  389.                 return -1;
  390.     }
  391.     /* We were able to remove the file from the disk */
  392.     return 0;
  393. }
  394.  
  395. /* Remove a directory and everything it contains.  Returns 0 for
  396.  * success, -1 for failure (in which case errno is set).
  397.  */
  398.  
  399. static int
  400. deep_remove_dir (path)
  401.     const char *path;
  402. {
  403.     DIR          *dirp;
  404.     struct dirent *dp;
  405.     char       buf[PATH_MAX];
  406.  
  407.     if ( rmdir (path) != 0 && errno == EACCESS )
  408.     {
  409.     if ((dirp = opendir (path)) == NULL)
  410.         /* If unable to open the directory return
  411.          * an error
  412.          */
  413.         return -1;
  414.  
  415.     while ((dp = readdir (dirp)) != NULL)
  416.     {
  417.         if (strcmp (dp->d_name, ".") == 0 ||
  418.             strcmp (dp->d_name, "..") == 0)
  419.         continue;
  420.  
  421.         sprintf (buf, "%s/%s", path, dp->d_name);
  422.  
  423.         if (unlink_file (buf) != 0 )
  424.         {
  425.         if (errno == EACCES)
  426.         {
  427.             if (deep_remove_dir (buf))
  428.             {
  429.             closedir (dirp);
  430.             return -1;
  431.             }
  432.         }
  433.         else
  434.         {
  435.             /* buf isn't a directory, or there are
  436.              * some sort of permision problems
  437.              */
  438.             closedir (dirp);
  439.             return -1;
  440.         }
  441.         }
  442.     }
  443.     closedir (dirp);
  444.     return rmdir (path);
  445.     }
  446.     /* Was able to remove the directory return 0 */
  447.     return 0;
  448. }
  449.  
  450.  
  451. /*
  452.  * Rename a file and die if it fails
  453.  */
  454. void
  455. rename_file (from, to)
  456.     const char *from;
  457.     const char *to;
  458. {
  459.     if (trace)
  460. #ifdef SERVER_SUPPORT
  461.     (void) fprintf (stderr, "%c-> rename(%s,%s)\n",
  462.             (server_active) ? 'S' : ' ', from, to);
  463. #else
  464.     (void) fprintf (stderr, "-> rename(%s,%s)\n", from, to);
  465. #endif
  466.     if (noexec)
  467.     return;
  468.  
  469.     unlink_file (to);
  470.     if (rename (from, to) != 0)
  471.     error (1, errno, "cannot rename file %s to %s", from, to);
  472. }
  473.  
  474.  
  475. /* Read NCHARS bytes from descriptor FD into BUF.
  476.    Return the number of characters successfully read.
  477.    The number returned is always NCHARS unless end-of-file or error.  */
  478. static size_t
  479. block_read (fd, buf, nchars)
  480.     int fd;
  481.     char *buf;
  482.     size_t nchars;
  483. {
  484.     char *bp = buf;
  485.     size_t nread;
  486.  
  487.     do 
  488.     {
  489.     nread = read (fd, bp, nchars);
  490.     if (nread == (size_t)-1)
  491.     {
  492. #ifdef EINTR
  493.         if (errno == EINTR)
  494.         continue;
  495. #endif
  496.         return (size_t)-1;
  497.     }
  498.  
  499.     if (nread == 0)
  500.         break; 
  501.  
  502.     bp += nread;
  503.     nchars -= nread;
  504.     } while (nchars != 0);
  505.  
  506.     return bp - buf;
  507.  
  508.     
  509. /*
  510.  * Compare "file1" to "file2". Return non-zero if they don't compare exactly.
  511.  */
  512. int
  513. xcmp (file1, file2)
  514.     const char *file1;
  515.     const char *file2;
  516. {
  517.     char *buf1, *buf2;
  518.     struct stat sb1, sb2;
  519.     int fd1, fd2;
  520.     int ret;
  521.  
  522.     if ((fd1 = open (file1, O_RDONLY | O_BINARY)) < 0)
  523.     error (1, errno, "cannot open file %s for comparing", file1);
  524.     if ((fd2 = open (file2, O_RDONLY | O_BINARY)) < 0)
  525.     error (1, errno, "cannot open file %s for comparing", file2);
  526.     if (fstat (fd1, &sb1) < 0)
  527.     error (1, errno, "cannot fstat %s", file1);
  528.     if (fstat (fd2, &sb2) < 0)
  529.     error (1, errno, "cannot fstat %s", file2);
  530.  
  531.     /* A generic file compare routine might compare st_dev & st_ino here 
  532.        to see if the two files being compared are actually the same file.
  533.        But that won't happen in CVS, so we won't bother. */
  534.  
  535.     if (sb1.st_size != sb2.st_size)
  536.     ret = 1;
  537.     else if (sb1.st_size == 0)
  538.     ret = 0;
  539.     else
  540.     {
  541.     /* FIXME: compute the optimal buffer size by computing the least
  542.        common multiple of the files st_blocks field */
  543.     size_t buf_size = 8 * 1024;
  544.     size_t read1;
  545.     size_t read2;
  546.  
  547.     buf1 = xmalloc (buf_size);
  548.     buf2 = xmalloc (buf_size);
  549.  
  550.     do 
  551.     {
  552.         read1 = block_read (fd1, buf1, buf_size);
  553.         if (read1 == (size_t)-1)
  554.         error (1, errno, "cannot read file %s for comparing", file1);
  555.  
  556.         read2 = block_read (fd2, buf2, buf_size);
  557.         if (read2 == (size_t)-1)
  558.         error (1, errno, "cannot read file %s for comparing", file2);
  559.  
  560.         /* assert (read1 == read2); */
  561.  
  562.         ret = memcmp(buf1, buf2, read1);
  563.     } while (ret == 0 && read1 == buf_size);
  564.  
  565.     free (buf1);
  566.     free (buf2);
  567.     }
  568.     
  569.     (void) close (fd1);
  570.     (void) close (fd2);
  571.     return (ret);
  572. }
  573.  
  574.  
  575. /* The equivalence class mapping for filenames.
  576.    OS/2 filenames are case-insensitive, but case-preserving.  Both /
  577.    and \ are path element separators. 
  578.    Thus, this table maps both upper and lower case to lower case, and
  579.    both / and \ to /.  
  580.  
  581.    Much thanks to Jim Blandy, who already invented this wheel in the
  582.    Windows NT port. */
  583.  
  584. #if 0
  585. main ()
  586. {
  587.   int c;
  588.  
  589.   for (c = 0; c < 256; c++)
  590.     {
  591.       int t;
  592.  
  593.       if (c == '\\')
  594.         t = '/';
  595.       else
  596.         t = tolower (c);
  597.       
  598.       if ((c & 0x7) == 0x0)
  599.          printf ("    ");
  600.       printf ("0x%02x,", t);
  601.       if ((c & 0x7) == 0x7)
  602.          putchar ('\n');
  603.       else if ((c & 0x7) == 0x3)
  604.          putchar (' ');
  605.     }
  606. }
  607. #endif
  608.  
  609.  
  610. unsigned char
  611. OS2_filename_classes[] =
  612. {
  613.     0x00,0x01,0x02,0x03, 0x04,0x05,0x06,0x07,
  614.     0x08,0x09,0x0a,0x0b, 0x0c,0x0d,0x0e,0x0f,
  615.     0x10,0x11,0x12,0x13, 0x14,0x15,0x16,0x17,
  616.     0x18,0x19,0x1a,0x1b, 0x1c,0x1d,0x1e,0x1f,
  617.     0x20,0x21,0x22,0x23, 0x24,0x25,0x26,0x27,
  618.     0x28,0x29,0x2a,0x2b, 0x2c,0x2d,0x2e,0x2f,
  619.     0x30,0x31,0x32,0x33, 0x34,0x35,0x36,0x37,
  620.     0x38,0x39,0x3a,0x3b, 0x3c,0x3d,0x3e,0x3f,
  621.     0x40,0x61,0x62,0x63, 0x64,0x65,0x66,0x67,
  622.     0x68,0x69,0x6a,0x6b, 0x6c,0x6d,0x6e,0x6f,
  623.     0x70,0x71,0x72,0x73, 0x74,0x75,0x76,0x77,
  624.     0x78,0x79,0x7a,0x5b, 0x2f,0x5d,0x5e,0x5f,
  625.     0x60,0x61,0x62,0x63, 0x64,0x65,0x66,0x67,
  626.     0x68,0x69,0x6a,0x6b, 0x6c,0x6d,0x6e,0x6f,
  627.     0x70,0x71,0x72,0x73, 0x74,0x75,0x76,0x77,
  628.     0x78,0x79,0x7a,0x7b, 0x7c,0x7d,0x7e,0x7f,
  629.     0x80,0x81,0x82,0x83, 0x84,0x85,0x86,0x87,
  630.     0x88,0x89,0x8a,0x8b, 0x8c,0x8d,0x8e,0x8f,
  631.     0x90,0x91,0x92,0x93, 0x94,0x95,0x96,0x97,
  632.     0x98,0x99,0x9a,0x9b, 0x9c,0x9d,0x9e,0x9f,
  633.     0xa0,0xa1,0xa2,0xa3, 0xa4,0xa5,0xa6,0xa7,
  634.     0xa8,0xa9,0xaa,0xab, 0xac,0xad,0xae,0xaf,
  635.     0xb0,0xb1,0xb2,0xb3, 0xb4,0xb5,0xb6,0xb7,
  636.     0xb8,0xb9,0xba,0xbb, 0xbc,0xbd,0xbe,0xbf,
  637.     0xc0,0xc1,0xc2,0xc3, 0xc4,0xc5,0xc6,0xc7,
  638.     0xc8,0xc9,0xca,0xcb, 0xcc,0xcd,0xce,0xcf,
  639.     0xd0,0xd1,0xd2,0xd3, 0xd4,0xd5,0xd6,0xd7,
  640.     0xd8,0xd9,0xda,0xdb, 0xdc,0xdd,0xde,0xdf,
  641.     0xe0,0xe1,0xe2,0xe3, 0xe4,0xe5,0xe6,0xe7,
  642.     0xe8,0xe9,0xea,0xeb, 0xec,0xed,0xee,0xef,
  643.     0xf0,0xf1,0xf2,0xf3, 0xf4,0xf5,0xf6,0xf7,
  644.     0xf8,0xf9,0xfa,0xfb, 0xfc,0xfd,0xfe,0xff,
  645. };
  646.  
  647. /* Like strcmp, but with the appropriate tweaks for file names.
  648.    Under OS/2, filenames are case-insensitive but case-preserving, and
  649.    both \ and / are path element separators.  */ 
  650. int
  651. fncmp (const char *n1, const char *n2)
  652. {
  653.     while (*n1 && *n2
  654.            && (OS2_filename_classes[(unsigned char) *n1]
  655.            == OS2_filename_classes[(unsigned char) *n2]))
  656.         n1++, n2++;
  657.     return (OS2_filename_classes[(unsigned char) *n1]
  658.             - OS2_filename_classes[(unsigned char) *n1]);
  659. }
  660.  
  661. /* Fold characters in FILENAME to their canonical forms.  
  662.    If FOLD_FN_CHAR is not #defined, the system provides a default
  663.    definition for this.  */
  664. void
  665. fnfold (char *filename)
  666. {
  667.     while (*filename)
  668.     {
  669.         *filename = FOLD_FN_CHAR (*filename);
  670.     filename++;
  671.     }
  672. }
  673.  
  674.  
  675. /* Return non-zero iff FILENAME is absolute.
  676.    Trivial under Unix, but more complicated under other systems.  */
  677. int
  678. isabsolute (filename)
  679.     const char *filename;
  680. {
  681.     return (ISDIRSEP (filename[0])
  682.             || (filename[0] != '\0'
  683.                 && filename[1] == ':'
  684.                 && ISDIRSEP (filename[2])));
  685. }
  686.  
  687. /* Return a pointer into PATH's last component.  */
  688. char *
  689. last_component (char *path)
  690. {
  691.     char *scan;
  692.     char *last = 0;
  693.  
  694.     for (scan = path; *scan; scan++)
  695.         if (ISDIRSEP (*scan))
  696.         last = scan;
  697.  
  698.     if (last)
  699.         return last + 1;
  700.     else
  701.         return path;
  702. }
  703.  
  704.  
  705. /* Read data from INFILE, and copy it to OUTFILE. 
  706.    Open INFILE using INFLAGS, and OUTFILE using OUTFLAGS.
  707.    This is useful for converting between CRLF and LF line formats.  */
  708. void
  709. convert_file (char *infile,  int inflags,
  710.           char *outfile, int outflags)
  711. {
  712.     int infd, outfd;
  713.     char buf[8192];
  714.     int len;
  715.  
  716.     if ((infd = open (infile, inflags, S_IREAD | S_IWRITE)) < 0)
  717.         error (1, errno, "couldn't read %s", infile);
  718.     if ((outfd = open (outfile, outflags, S_IREAD | S_IWRITE)) < 0)
  719.         error (1, errno, "couldn't write %s", outfile);
  720.  
  721.     while ((len = read (infd, buf, sizeof (buf))) > 0)
  722.         if (write (outfd, buf, len) < 0)
  723.         error (1, errno, "error writing %s", outfile);
  724.     if (len < 0)
  725.         error (1, errno, "error reading %s", infile);
  726.  
  727.     if (close (outfd) < 0)
  728.         error (0, errno, "warning: couldn't close %s", outfile);
  729.     if (close (infd) < 0)
  730.         error (0, errno, "warning: couldn't close %s", infile);
  731. }
  732.  
  733. /* Return the home directory.  Returns a pointer to storage
  734.    managed by this function or its callees (currently getenv).  */
  735. char *
  736. get_homedir ()
  737. {
  738.     return getenv ("HOME");
  739. }
  740.  
  741. /* See cvs.h for description.  On OS/2 this does nothing, but it probably
  742.    should be expanding wildcards like on NT.  */
  743. void
  744. expand_wild (argc, argv, pargc, pargv)
  745.     int argc;
  746.     char **argv;
  747.     int *pargc;
  748.     char ***pargv;
  749. {
  750.     int i;
  751.     *pargc = argc;
  752.     *pargv = (char **) xmalloc (argc * sizeof (char *));
  753.     for (i = 0; i < argc; ++i)
  754.     (*pargv)[i] = xstrdup (argv[i]);
  755. }
  756.